#include <linux/kernel.h>       /**< printk() */
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>

#define MIN(a,b) ((a)<(b)?(a):(b))
// 1. 确定主设备号
static int major =0; // 自动获取设备号
static char hello_buf[1024];
static struct class *hello_cls;
static struct device *hello_dev;
// 3. 文件方法
//文件打开函数
static int hello_open(struct inode *inode, struct file *filp)
{
    printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);

    return 0;
}

//文件关闭函数
static int hello_release(struct inode *inode, struct file *pfile)
{
    printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
    return 0;
}

//文件读取函数
static ssize_t hello_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
    printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
    copy_to_user(buf, hello_buf,MIN(1024, size));
    return MIX(1024, size);
}

//文件写入函数
static ssize_t hello_write( struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
    printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
    copy_from_user(hello_buf, buf, MIN(1024, size));
    return MIX(1024, size);
}

// 2. 定义文件操作集合
struct file_operations hello_fops {
    .owner		= THIS_MODULE,
    .open       = hello_open,
    .release    = hello_release,
    .read       = hello_read,
    .write      = hello_write,
}

// 4. 定义驱动加载函数
static void __init hello_init(void)
{
    printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);

    // 4.1 注册主设备号
    major = register_chrdev(0,"hello",&hello_fops);

    // 4.2 注册类
    hello_cls = class_create(THIS_MODULE, "hello_class");
    if (IS_ERR(hello_cls)){
        printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
        unregister_chardev(major,"hello");
        return -EBUSY;
    }

    // 4.3 注册设备
    device_class = device_create(hello_class, NULL, MKDEV(major,0), NULL, "hello_dev");
    
    if(IS_ERR(device_class))
	{
        // 注销 类
		class_destroy(hello_cls);
		unregister_chrdev(major,"hello");
		return -EBUSY;
	}

    return 0;
}

// 5. 定义驱动卸载函数
static void __exit hello_exit(void)
{
    printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
    // 按照 注册的 逆顺序卸载
    device_destroy(hello_class,MKDEV(major, 0));
    class_destroy(hello_class);
    unregister_chardev(major,"hello");
}

// 6. 模块
MODULE_LICENSE("GPL");

module_init(hello_init);
module_exit(hello_exit);
